/*
 * SPI.c
 *
 * Created: 20.02.2013 15:35:54
 *  Author: saenko
 */ 
#include <avr/io.h>
#include <avr/interrupt.h>

#define cbi(reg,bit)	reg &= ~(_BV(bit))
#define sbi(reg,bit)	reg |= (_BV(bit))

#define SPI_PORT PORTB
#define SPI_DDR  DDRB
#define SPI_PIN  PINB

#define SS PB2
#define SCK PB5
#define SPI_OUT PB3
#define SPI_IN PB4

#define SET_SS	sbi(SPI_PORT,SS)
#define CLR_SS	cbi(SPI_PORT,SS)

#define SPI_OUT_1 sbi(SPI_PORT,SPI_OUT)
#define SPI_OUT_0 cbi(SPI_PORT,SPI_OUT)

#define SCK_1 sbi(SPI_PORT,SCK)
#define SCK_0 cbi(SPI_PORT,SCK)

unsigned char buf[16];

void delay_half(void)
{
	asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
	asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
	
}


void spi_init(void)
{
	sbi(SPI_DDR,SPI_OUT);
	sbi(SPI_DDR,SCK);
	sbi(SPI_DDR,SS);
	cbi(SPI_DDR,SPI_IN);
	
	cbi(SPI_PORT,SCK);
	cbi(SPI_PORT,SPI_OUT);
	sbi(SPI_PORT,SS);
	cbi(SPI_PORT,SPI_IN);
}

void start_init(void)
{
	cbi(SPI_PORT,SS);
	delay_half();
}

void stop_init(void)
{
	sbi(SPI_PORT,SS);
}

void spi_write(unsigned char data)
{
	SPDR = data;
}

unsigned char spi_read_one_reg(unsigned char reg)
{
	unsigned char data_in;
	
	reg = (reg & 0b00011111) + 0b01000000;
	
	start_init();
	for(unsigned char i = 0; i < 8; i++)
	{
		if(bit_is_set(reg,7-i)) SPI_OUT_1;
		else SPI_OUT_0;
		
		delay_half();
		
		SCK_1;
		
		delay_half();
		
		SCK_0;
	}
	
	delay_half();
	
	for(unsigned char i = 0; i < 8; i++)
	{
		SCK_1;
		
		delay_half();
		
		SCK_0;
		
		data_in = data_in << 1;
				
		if(bit_is_set(SPI_PIN,SPI_IN)) data_in++;
		//else data_in = data_in & 0b01111111;
		
		
		delay_half();
	}	
	
	stop_init();
	
	return data_in;
}

void spi_read_regs(unsigned char first_reg,unsigned char num_bytes)
{
	
	unsigned char data_in;
	
	first_reg = (first_reg & 0b00011111) + 0b01100000;
			
	start_init();

	for(unsigned char i = 0; i < 8; i++)
	{
		if(bit_is_set(first_reg,7-i)) SPI_OUT_1;
		else SPI_OUT_0;
				
		delay_half();
				
		SCK_1;
				
		delay_half();
				
		SCK_0;
	}
			
	delay_half();
		
	for(unsigned char i =0 ; i<num_bytes; i++)
	{
			data_in = 0;
			
			for(unsigned char i = 0; i < 8; i++)
			{
				SCK_1;
				
				delay_half();
				
				SCK_0;
				
				data_in = data_in << 1;
				
				if(bit_is_set(SPI_PIN,SPI_IN)) data_in++;
				//else data_in = data_in & 0b01111111;
				
				
				delay_half();
			}
			
			buf[i] = data_in;
			
	}
	
	stop_init();
	
}

void spi_write_one_reg(unsigned char reg, unsigned char data)
{
	reg = reg & 0b00011111;
		
	start_init();
	
	for(unsigned char i = 0; i < 8; i++)
	{
		if(reg&0b10000000) SPI_OUT_1;
		else SPI_OUT_0;
			
		reg<<1;
			
		delay_half();
			
		SCK_1;
			
		delay_half();
			
		SCK_0;
	}
	
	for(unsigned char i = 0; i < 8; i++)
	{
		if(data&0b10000000) SPI_OUT_1;
		else SPI_OUT_0;
			
		reg<<1;
			
		delay_half();
			
		SCK_1;
			
		delay_half();
			
		SCK_0;
	}
	
	stop_init();
	
}

void spi_write_from_buf(unsigned char num)
{
	start_init();
	
	unsigned char data;
	
	for(unsigned char j=0; j<num; j++)
	{
		data = buf[j];
		
		for(unsigned char i = 0; i < 8; i++)
		{
			if(bit_is_set(data,7-i)) SPI_OUT_1;
			else SPI_OUT_0;
			
			delay_half();
			
			SCK_1;
			
			delay_half();
			
			SCK_0;
		}
		
		
	}
	
	stop_init();
}


unsigned char spi_read_IRQ_status(void)
{
	unsigned char data = 0x6C;
	unsigned char data_in;
	
	start_init();
	
	for(unsigned char i = 0; i <8; i++)
	{
		if(bit_is_set(data,7-i)) SPI_OUT_1;
		else SPI_OUT_0;
		
		delay_half();
		SCK_1;
		delay_half();
		SCK_0;
	}
	
	delay_half();

	for(unsigned char i = 0; i <8; i++)
	{
		SCK_1;
		delay_half();
		SCK_0;
		data_in = data_in<<1;
		if(bit_is_set(PINB,SPI_IN)) data_in++;
		//else data_in<<0;
		delay_half();
		

	}
	
	for(unsigned char i = 0; i <8; i++)
	{
		SCK_1;
		delay_half();
		SCK_0;
		delay_half();
		

	}
	
	stop_init();
	
	return data_in;
}

